// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_ui_window.h"
#include "mk_error.h"
#include "mk_math.h"
#include "mk_ui_manager.h"

namespace MK3DE
{
    DWORD CUIWindow::__id = 0;
    CUIWindow* CUIWindow::_s_mouseHover = NULL;
    CUIWindow* CUIWindow::_s_focus = NULL;

    DWORD CUIWindow::UIDAC_PANEL_BG_NORMAL[4] = { 0x800000ff, 0x800000ff, 0x200000ff, 0x200000ff };
    DWORD CUIWindow::UIDAC_PANEL_BG_FOCUS[4] = { 0x80000080, 0x80000080, 0x80000080, 0x80000080 };
    DWORD CUIWindow::UIDAC_PANEL_BG_HOVER[4] = { 0x80000080, 0x80000080, 0x80000080, 0x80000080 };
    DWORD CUIWindow::UIDAC_BORDER_LIGHT[4] = { 0xffa0a0a0, 0xffa0a0a0, 0xffa0a0a0, 0xffa0a0a0 };
    DWORD CUIWindow::UIDAC_BORDER_DARK[4] = { 0xff404040, 0xff404040, 0xff404040, 0xff404040 };


    CUIWindow::CUIWindow(CUIRenderer* renderer, CUIWindow* parent, D3DXVECTOR2& pos, D3DXVECTOR2& size, const char* name) :
        _renderer(renderer),
        _parent(parent),
        _pos(pos),
        _size(size),
        _name(name),
        _show(TRUE)
    {
        _id = __NewId();
        SetBorder(0);
    }

    CUIWindow::~CUIWindow()
    {
        DeleteChildren();
    }

    void CUIWindow::SetBorder(float border)
    {
        float size = border * 2;
        if (size < _size.y && size < _size.x)
            _border = border;
        _fontRender.SetPosition(_pos.x + _border, _pos.y + _border);
        _fontRender.SetSize(_size.x - size, _size.y - size);
    }

    BOOL CUIWindow::Show(BOOL show)
    {
        _show = show;
        std::vector<CUIWindow*>::iterator i = _children.begin();
        while (i != _children.end())
        {
            CUIWindow* win = *i;
            win->Show(show);
            ++i;
        }

        return TRUE;
    }

    BOOL CUIWindow::AddChild(CUIWindow* child)
    {
        CUIWindow* parent = child->GetParent();
        if (parent)
            parent->RemoveChild(child);
        _children.push_back(child);
        return TRUE;
    }

    BOOL CUIWindow::RemoveChild(CUIWindow* child)
    {
        std::vector<CUIWindow*>::iterator i = _children.begin();
        while (i != _children.end())
        {
            if ((*i) == child)
            {
                _children.erase(i);
                return TRUE;
            }

            ++i;
        }

        return FALSE;
    }

    CUIWindow* CUIWindow::GetChild(int id)
    {
        std::vector<CUIWindow*>::iterator i = _children.begin();
        while (i != _children.end())
        {
            if ((*i)->GetId() == id)
                return *i;

            ++i;
        }

        return NULL;
    }

    BOOL CUIWindow::DeleteChildren()
    {
        std::vector<CUIWindow*>::iterator i = _children.begin();
        while (i != _children.end())
        {
            CUIWindow* win = *i;
            SAFE_DELETE(win);
            ++i;
        }

        return TRUE;
    }

    BOOL CUIWindow::Update(DWORD dt)
    {
        std::vector<CUIWindow*>::iterator i = _children.begin();
        while (i != _children.end())
        {
            CUIWindow* win = *i;
            win->Update(dt);
            ++i;
        }

        return TRUE;
    }

    BOOL CUIWindow::Render()
    {
        std::vector<CUIWindow*>::iterator i = _children.begin();
        while (i != _children.end())
        {
            CUIWindow* win = *i;
            win->Render();
            ++i;
        }

        return TRUE;
    }

    BOOL CUIWindow::IsPointIn(D3DXVECTOR2* pt)
    {
        return IsPointInRect(&_pos, &D3DXVECTOR2(_pos.x + _size.x, _pos.y + _size.y), pt);
    }

    CUIWindow* CUIWindow::GetWindowAtPoint(D3DXVECTOR2* pt)
    {
        if (IsPointIn(pt))
        {
            std::vector<CUIWindow*>::iterator i = _children.begin();
            while (i != _children.end())
            {
                CUIWindow* win = *i;
                if (win->IsPointIn(pt))
                    return win;
                ++i;
            }

            return this;
        }

        return NULL;
    }

    void CUIWindow::SetMouseHover(CUIWindow* control)
    {
        if (control != _s_mouseHover)
        {
            if (_s_mouseHover)
                _s_mouseHover->OnMouseLeave();
            if (control)
                control->OnMouseEnter();
        }
        
        _s_mouseHover = control; 
    }

    void CUIWindow::SetFocus(CUIWindow* focus)
    {
        if (focus != _s_focus)
        {
            if (_s_focus)
                _s_focus->OnFocusLost();

            if (focus)
                focus->OnFocusSet();
        }

        _s_focus = focus; 
    }


    BOOL CUIWindow::MsgProc(UIInputEvent& event)
    {
        switch (event.type)
        {
        case UI_IET_LBUTTON_DOWN:
        case UI_IET_LBUTTON_UP:
        case UI_IET_LBUTTON_DCLICK:
            {
                CUIWindow* win = GetWindowAtPoint(&event.pos);
                if (win)
                {
                    CUIWindow::SetFocus(win);
                    return win->MouseMsgProc(event);
                }
                else if (CUIWindow::GetFocus() == this)
                {
                    CUIWindow::SetFocus(NULL);
                }
            }
            break;

        case UI_IET_MOUSE_MOVE:
            {
                CUIWindow* win = GetWindowAtPoint(&event.pos);
                if (win)
                {
                    CUIWindow::SetMouseHover(win);
                    return win->MouseMsgProc(event);
                }
                else if (CUIWindow::GetMouseHover() == this)
                {
                    CUIWindow::SetMouseHover(NULL);
                }
            }
            break;

        case UI_IET_CHAR:
            {
                return KeyboardMsgProc(event);
            }
            break;
        }

        return FALSE;
    }

    void CUIWindow::SetPosition(float x, float y)
    {
        _pos.x = x;
        _pos.y = y;
        _fontRender.SetPosition(x, y);
        _fontRender.Recalculate();
    }
}